﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using OWLServer.owl.tipos;

namespace OWLServer
{
    public partial class FOntologia : Form
    {
        // Constantes
        private const string NODO_ONTOLOGIA = "$%&Ontologia$%&";
        private const string NODO_ESPACIOS = "$%&Espacios$%&";
        private const string NODO_CLASES = "$%&Clases$%&";
        private const string NODO_PROP_DAT = "$%&PropDat$%&";
        private const string NODO_PROP_OBJ = "$%&PropObj$%&";
        private const string NODO_INDIVIDUOS = "$%&Individuos$%&";

        private const int ICONO_ONTOLOGIA = 0;
        private const int ICONO_ESPACIO = 1;
        private const int ICONO_CLASE = 2;
        private const int ICONO_PROPIEDAD_DATO = 3;
        private const int ICONO_PROPIEDAD_OBJETO = 4;
        private const int ICONO_INDIVIDUO = 5;

        private Ontologia onlologia;

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="ontologia">Ontologia que va a manejar el formulario</param>
        public FOntologia(Ontologia ontologia)
        {
            InitializeComponent();
            this.onlologia = ontologia;
        }

        /// <summary>
        /// Carga el TreeView con la otologia
        /// </summary>
        /// <param name="ontologia">Ontologia que se va a cargar en el treeView</param>
        private void cargarTreeView(Ontologia ontologia)
        {
            // Primer nivel
            TreeNode nOntologia = tvOntologia.Nodes.Add(onlologia.ToString(), onlologia.EspacioNombresPrincipal.Uri, NODO_ONTOLOGIA);
            cargarOntologia();
            nOntologia.Expand();
            // Segundos Niveles
            TreeNode nEspacios = nOntologia.Nodes.Add(NODO_ESPACIOS, string.Format("Espacios de Nombres ({0})", onlologia.EspaciosNombres.Count),ICONO_ESPACIO);
            cargarEspaciosNombresTreeView(onlologia, nEspacios);
            TreeNode nClases = nOntologia.Nodes.Add(NODO_CLASES, string.Format("Clases ({0})", onlologia.Clases.Count), ICONO_CLASE);
            cargarClasesTreeView(onlologia, nClases);
            TreeNode nPropiedadesObjetos = nOntologia.Nodes.Add(NODO_PROP_OBJ, string.Format("Propiedades de Objetos ({0})", onlologia.PropiedadesObjetos.Count), ICONO_PROPIEDAD_OBJETO);
            cargarPropiedadesObjetosTreeView(onlologia, nPropiedadesObjetos);
            TreeNode nPropiedadesDatos = nOntologia.Nodes.Add(NODO_PROP_DAT, string.Format("Propiedades de Datos ({0})", onlologia.PropiedadesDatos.Count), ICONO_PROPIEDAD_DATO);
            cargarPropiedadesDatosTreeView(onlologia, nPropiedadesDatos);
            TreeNode nIndividuos = nOntologia.Nodes.Add(NODO_INDIVIDUOS, string.Format("Individuos ({0})", onlologia.Individuos.Count), ICONO_INDIVIDUO);
            cargarIndividuosTreeView(onlologia, nIndividuos);
        }

        /// <summary>
        /// Carga los espacios de nombres de la ontologia en el treeview
        /// </summary>
        /// <param name="ontologia">Ontologia que estamos manejando</param>
        /// <param name="nodoPrincipal">Nodo donde se van a agregar los elementos</param>
        private void cargarEspaciosNombresTreeView(Ontologia ontologia, TreeNode nodoPrincipal)
        {
            foreach (EspacioNombres espacios in onlologia.EspaciosNombres)
            {
                nodoPrincipal.Nodes.Add(espacios.ToString(), espacios.Uri, ICONO_ESPACIO);
            }
        }

        /// <summary>
        /// Carga las clases de la ontologia en el treeview
        /// </summary>
        /// <param name="ontologia">Ontologia que estamos manejando</param>
        /// <param name="nodoPrincipal">Nodo donde se van a agregar los elementos</param>
        private void cargarClasesTreeView(Ontologia ontologia, TreeNode nodoPrincipal)
        {
            foreach (Clase clase in onlologia.Clases)
            {
                nodoPrincipal.Nodes.Add(clase.ToString(), clase.Id, ICONO_CLASE);
            }
        }

        /// <summary>
        /// Carga las propiedades de datos de la ontologia en el treeview
        /// </summary>
        /// <param name="ontologia">Ontologia que estamos manejando</param>
        /// <param name="nodoPrincipal">Nodo donde se van a agregar los elementos</param>
        private void cargarPropiedadesDatosTreeView(Ontologia ontologia, TreeNode nodoPrincipal)
        {
            foreach (Propiedad propiedad in onlologia.PropiedadesDatos)
            {
                nodoPrincipal.Nodes.Add(propiedad.ToString(), propiedad.Id, ICONO_PROPIEDAD_DATO);
            }
        }

        /// <summary>
        /// Carga las propiedades de objetos de la ontologia en el treeview
        /// </summary>
        /// <param name="ontologia">Ontologia que estamos manejando</param>
        /// <param name="nodoPrincipal">Nodo donde se van a agregar los elementos</param>
        private void cargarPropiedadesObjetosTreeView(Ontologia ontologia, TreeNode nodoPrincipal)
        {
            foreach (PropiedadObjeto propiedad in onlologia.PropiedadesObjetos)
            {
                nodoPrincipal.Nodes.Add(propiedad.ToString(), propiedad.Id, ICONO_PROPIEDAD_OBJETO);
            }
        }

        /// <summary>
        /// Carga los individuos de la ontologia en el treeview
        /// </summary>
        /// <param name="ontologia">Ontologia que estamos manejando</param>
        /// <param name="nodoPrincipal">Nodo donde se van a agregar los elementos</param>
        private void cargarIndividuosTreeView(Ontologia ontologia, TreeNode nodoPrincipal)
        {
            foreach (Individuo individuo in onlologia.Individuos)
            {
                nodoPrincipal.Nodes.Add(individuo.ToString(), individuo.Id, ICONO_INDIVIDUO);
            }
        }

        /// <summary>
        /// Load del formulario
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FOntologia_Load(object sender, EventArgs e)
        {
            cargarTreeView(onlologia);
        }

        /// <summary>
        /// Evento al seleccionar en el TreeView
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tvOntologia_AfterSelect(object sender, TreeViewEventArgs e)
        {
            if (e.Node.IsExpanded)
            {
                e.Node.Collapse();
            }
            else
            {
                e.Node.Expand();
            }

            ocultarPropiedades();

            switch (e.Node.Level) {
                case 0:
                    // Ontologia
                    cargarOntologia();
                    break;

                case 1:
                    // Nada
                    break;

                case 2:
                    switch (e.Node.Parent.Name) {
                        case NODO_CLASES:
                            cargarClase(e.Node.Name);
                            break;
                        case NODO_ESPACIOS:
                            cargarEspacio(e.Node.Name);
                            break;
                        case NODO_PROP_DAT:
                            cargarPropiedadDato(e.Node.Name);
                            break;
                        case NODO_PROP_OBJ:
                            cargarPropiedadObjeto(e.Node.Name);
                            break;
                        case NODO_INDIVIDUOS:
                            cargarIndividuo(e.Node.Name);
                            break;
                    }
                    break;
            }
        }

        /// <summary>
        /// Cargar la informacion de la ontologia
        /// </summary>
        /// <param name="key">Key del elemento seleccionado</param>
        private void cargarOntologia()
        {
            rtbOWL.Text = onlologia.Owl;

            gbOWL.Visible = true;
        }

        /// <summary>
        /// Cargar la informacion del Espacio de nombres seleccionado
        /// </summary>
        /// <param name="key">Key del elemento seleccionado</param>
        private void cargarEspacio(string key)
        {
            EspacioNombres espacio = onlologia.getEspaciosNombresDictiorary()[key];

            tNombreEspacio.Text = espacio.Nombre;
            tUriEspacio.Text = espacio.Uri;

            gbEspacioNombres.Visible = true;
        }

        /// <summary>
        /// Cargar la informacion de la clase seleccionado
        /// </summary>
        /// <param name="key">Key del elemento seleccionado</param>
        private void cargarClase(string key)
        {
            Clase clase = onlologia.getClasesDictiorary()[key];

            tNombreClase.Text = clase.Id;
            tEspacioClase.Text = clase.EspacioNombres.Uri;

            cargarListaClases(lvDijuntasClase, clase.Disjuntas, false);
            cargarListaUnionesClasesDisjuntas(lvDijuntasClase, clase.UnionesClasesDisjuntas, true);
            cargarListaClases(lvHijasClase, clase.HijasClases, false);
            cargarListaClases(lvIgualesClase, clase.Equivalentes, false);
            cargarListaClases(lvPadresClase, clase.PadreClases, false);
            cargarListaPropiedades(lvClavesClase, clase.ClavesPropiedadDato, false);
            cargarListaPropiedades(lvClavesClase, clase.ClavesPropiedadObjeto, true);
            cargaListaRestriccionesClases(clase);

            gbClases.Visible = true;
        }

        /// <summary>
        /// Cargar la informacion de la propiedad dato seleccionada
        /// </summary>
        /// <param name="key">Key del elemento seleccionado</param>
        private void cargarPropiedadDato(string key)
        {
            Propiedad propiedad = onlologia.getPropiedadesDatosDictiorary()[key];

            tNombrePropiedadDato.Text = propiedad.Id;
            tEspacioNombrePropiedadDato.Text = propiedad.EspacioNombres.Uri;

            cargarListaClases(lvDominioPropiedadDato, propiedad.Dominios, false);
            cargarListaClases(lvRangoPropiedadDato, propiedad.Rangos, false);
            cargarListaTiposPropiedades(lvTiposPropiedadDato, propiedad.Tipos, false);
            cargarListaPropiedades(lvHijasPropiedadDato, propiedad.SubPropiedades, false);
            cargarListaPropiedades(lvPadresPropiedadDato, propiedad.PadrePropiedades, false);
            cargarListaPropiedades(lvEquivalentesPropiedadDato, propiedad.EquivalentesPropiedades, false);
            cargarListaPropiedades(lvDisjuntasPropiedadDato, propiedad.DisjuntasPropiedades, false);
            cargaListaRestriccionesPropiedadesDato(propiedad);

            gbPropiedadesDato.Visible = true;
        }

        /// <summary>
        /// Cargar la informacion de la propiedad objeto seleccionado
        /// </summary>
        /// <param name="key">Key del elemento seleccionado</param>
        private void cargarPropiedadObjeto(string key)
        {
            PropiedadObjeto propiedad = onlologia.getPropiedadesObjetosDictiorary()[key] as PropiedadObjeto;

            tNombrePropiedadObjeto.Text = propiedad.Id;
            tEspacioPropiedadObjeto.Text = propiedad.EspacioNombres.Uri;

            cargarListaClases(lvDominioPropiedadObjeto, propiedad.Dominios, false);
            cargarListaClases(lvRangoPropiedadObjeto, propiedad.Rangos, false);
            cargarListaTiposPropiedades(lvTiposPropiedadObjeto, propiedad.Tipos, false);
            cargarListaPropiedades(lvHijasPropiedadObjeto, propiedad.SubPropiedades, false);
            cargarListaPropiedades(lvPadresPropiedadObjeto, propiedad.PadrePropiedades, false);
            cargarListaPropiedades(lvEquivalentesPropiedadObjeto, propiedad.EquivalentesPropiedades, false);
            cargarListaPropiedades(lvDisjuntasPropiedadObjeto, propiedad.DisjuntasPropiedades, false);
            cargarListaPropiedades(lvInversasPropiedadObjeto, propiedad.InversosPropiedadesObjeto, false);
            cargaListaRestriccionesPropiedadesObjeto(propiedad);

            gbPropiedadObjeto.Visible = true;
        }

        /// <summary>
        /// Cargar la informacion del individuo seleccionado
        /// </summary>
        /// <param name="key">Key del elemento seleccionado</param>
        private void cargarIndividuo(string key)
        {
            Individuo individuo = onlologia.getIndividuosDictiorary()[key];

            tNombreIndividuo.Text = individuo.Id;
            tEspacioIndividuo.Text = individuo.EspacioNombres.Uri;

            cargarListaClases(lvTiposIndividuo, individuo.Tipos, false);
            cargarListaPropiedadesIndividuo(lvPropiedadesDatosIndividuo, individuo.PropiedadesDatos, false);
            cargarListaPropiedadesIndividuo(lvPropiedadesObjetoIndividuo, individuo.PropiedadesObjetos, false);
            cargarListaIndividuos(lvIgualesIndividuo, individuo.Iguales, false);
            cargarListaIndividuos(lvDiferentesIndividuo, individuo.Diferentes, false);
            cargaListaRestriccionesIndividuo(individuo);

            gbIndividuos.Visible = true;
        }

        /// <summary>
        /// Carga la lista de las clases que le pasemos
        /// </summary>
        /// <param name="lista">Lista que vamos a cargar</param>
        /// <param name="clases">Clases a cargar</param>
        /// <param name="sumar">Si agrega o no a las que tiene la lista</param>
        private void cargarListaClases(ListView lista, IList<Clase> clases, bool sumar)
        {
            if (!sumar)
            {
                lista.Items.Clear();
            }

            foreach (Clase clase in clases)
            {
                lista.Items.Add(clase.ToString());
            }
        }

        /// <summary>
        /// Carga la lista de los individuos que le pasemos
        /// </summary>
        /// <param name="lista">Lista que vamos a cargar</param>
        /// <param name="individuos">Individuos a cargar</param>
        /// <param name="sumar">Si agrega o no a las que tiene la lista</param>
        private void cargarListaIndividuos(ListView lista, IList<Individuo> individuos, bool sumar)
        {
            if (!sumar)
            {
                lista.Items.Clear();
            }

            foreach (Individuo individuo in individuos)
            {
                lista.Items.Add(individuo.ToString());
            }
        }

        /// <summary>
        /// Carga la lista de los tipos de propiedades que le pasemos
        /// </summary>
        /// <param name="lista">Lista que vamos a cargar</param>
        /// <param name="tipos">Clases a cargar</param>
        /// <param name="sumar">Si agrega o no a las que tiene la lista</param>
        private void cargarListaTiposPropiedades(ListView lista, IList<TipoPropiedad> tipos, bool sumar)
        {
            if (!sumar)
            {
                lista.Items.Clear();
            }

            foreach (TipoPropiedad tipo in tipos)
            {
                lista.Items.Add(tipo.ToString());
            }
        }

        /// <summary>
        /// Carga la lista de las propiedades que le pasemos
        /// </summary>
        /// <param name="lista">Lista que vamos a cargar</param>
        /// <param name="propiedades">Propiedades a cargar</param>
        /// <param name="sumar">Si agrega o no a las que tiene la lista</param>
        private void cargarListaPropiedades(ListView lista, IList<Propiedad> propiedades, bool sumar)
        {
            if (!sumar)
            {
                lista.Items.Clear();
            }

            foreach (Propiedad propiedad in propiedades)
            {
                lista.Items.Add(propiedad.ToString());
            }
        }

        /// <summary>
        /// Carga la lista de las propiedades que le pasemos
        /// </summary>
        /// <param name="lista">Lista que vamos a cargar</param>
        /// <param name="propiedades">Propiedades a cargar</param>
        /// <param name="sumar">Si agrega o no a las que tiene la lista</param>
        private void cargarListaPropiedades(ListView lista, IList<PropiedadObjeto> propiedades, bool sumar)
        {
            if (!sumar)
            {
                lista.Items.Clear();
            }

            foreach (Propiedad propiedad in propiedades)
            {
                lista.Items.Add(propiedad.ToString());
            }
        }

        /// <summary>
        /// Carga la lista de las propiedades que le pasemos
        /// </summary>
        /// <param name="lista">Lista que vamos a cargar</param>
        /// <param name="propiedades">Propiedades a cargar</param>
        /// <param name="sumar">Si agrega o no a las que tiene la lista</param>
        private void cargarListaPropiedadesIndividuo(ListView lista, IList<PropiedadDatoIndividuo> propiedades, bool sumar)
        {
            if (!sumar)
            {
                lista.Items.Clear();
            }

            foreach (PropiedadDatoIndividuo propiedad in propiedades)
            {
                lista.Items.Add(propiedad.ToString());
            }
        }

        /// <summary>
        /// Carga la lista de las propiedades que le pasemos
        /// </summary>
        /// <param name="lista">Lista que vamos a cargar</param>
        /// <param name="propiedades">Propiedades a cargar</param>
        /// <param name="sumar">Si agrega o no a las que tiene la lista</param>
        private void cargarListaPropiedadesIndividuo(ListView lista, IList<PropiedadObjetoIndividuo> propiedades, bool sumar)
        {
            if (!sumar)
            {
                lista.Items.Clear();
            }

            foreach (PropiedadObjetoIndividuo propiedad in propiedades)
            {
                lista.Items.Add(propiedad.ToString());
            }
        }

        /// <summary>
        /// Carga la lista de las uniones de clases disjuntas que le pasemos
        /// </summary>
        /// <param name="lista">Lista que vamos a cargar</param>
        /// <param name="propiedades">Uniones de clases disjuntas a cargar</param>
        /// <param name="sumar">Si agrega o no a las que tiene la lista</param>
        private void cargarListaUnionesClasesDisjuntas(ListView lista, IList<UnionClasesDisjuntas> uniones, bool sumar)
        {
            if (!sumar)
            {
                lista.Items.Clear();
            }

            StringBuilder sb;
            int sizeClases;

            foreach (UnionClasesDisjuntas union in uniones)
            {
                sb = new StringBuilder();
                sizeClases = union.ElementosUnionClasesDisjuntas.Count;

                if (sizeClases > 0)
                {
                    sb.Append("[");
                    for (int i = 0; i < sizeClases - 1; i++)
                    {
                        sb.Append(union.ElementosUnionClasesDisjuntas[i].ToString());
                        sb.Append("; ");
                    }
                    sb.Append(union.ElementosUnionClasesDisjuntas[sizeClases - 1].ToString());
                    sb.Append("]");
                    lista.Items.Add(sb.ToString());
                }
            }
        }

        /// <summary>
        /// Carga las restricciones aplicadas a las clases
        /// </summary>
        /// <param name="clase"></param>
        private void cargaListaRestriccionesClases(Clase clase)
        {
            lvRestriccionesEqui.Items.Clear();
            lvRestriccionesSub.Items.Clear();

            // Restricciones de propiedad de dato
            foreach (RestriccionPropiedadDato restriccion in clase.RestriccionesPropiedadDato)
            {
                if (restriccion.TipoPropiedadRelacionada == TipoPropiedadRelacionada.CLASE_EQUIVALENTE)
                {
                    lvRestriccionesEqui.Items.Add(restriccion.ToString());
                }
                else if (restriccion.TipoPropiedadRelacionada == TipoPropiedadRelacionada.CLASE_SUBCLASE)
                {
                    lvRestriccionesSub.Items.Add(restriccion.ToString());
                }
            }

            // Restricciones de propiedad de dato
            foreach (RestriccionPropiedadObjeto restriccion in clase.RestriccionesPropiedadObjeto)
            {
                if (restriccion.TipoPropiedadRelacionada == TipoPropiedadRelacionada.CLASE_EQUIVALENTE)
                {
                    lvRestriccionesEqui.Items.Add(restriccion.ToString());
                }
                else if (restriccion.TipoPropiedadRelacionada == TipoPropiedadRelacionada.CLASE_SUBCLASE)
                {
                    lvRestriccionesSub.Items.Add(restriccion.ToString());
                }
            }
        }

        /// <summary>
        /// Carga las restricciones aplicadas a las propiedades de datos
        /// </summary>
        /// <param name="propiedad"></param>
        private void cargaListaRestriccionesPropiedadesDato(Propiedad propiedad)
        {
            lvRestriccionesDominioPropDato.Items.Clear();

            // Restricciones de propiedad de dato
            foreach (RestriccionPropiedadDato restriccion in propiedad.RestriccionesPropiedadDato)
            {
                if (restriccion.TipoPropiedadRelacionada == TipoPropiedadRelacionada.PROPIEDAD_DATO_DOMINIO)
                {
                    lvRestriccionesDominioPropDato.Items.Add(restriccion.ToString());
                }
            }

            // Restricciones de propiedad de dato
            foreach (RestriccionPropiedadObjeto restriccion in propiedad.RestriccionesPropiedadObjeto)
            {
                if (restriccion.TipoPropiedadRelacionada == TipoPropiedadRelacionada.PROPIEDAD_DATO_DOMINIO)
                {
                    lvRestriccionesDominioPropDato.Items.Add(restriccion.ToString());
                }
            }
        }

        /// <summary>
        /// Carga las restricciones aplicadas a las propiedades de objeto
        /// </summary>
        /// <param name="propiedad"></param>
        private void cargaListaRestriccionesPropiedadesObjeto(PropiedadObjeto propiedad)
        {
            lvRestriccionDominioPropiedadObjeto.Items.Clear();
            lvRestriccionRangoPropiedadObjeto.Items.Clear();

            // Restricciones de propiedad de dato
            foreach (RestriccionPropiedadDato restriccion in propiedad.RestriccionesPropiedadDato)
            {
                if (restriccion.TipoPropiedadRelacionada == TipoPropiedadRelacionada.PROPIEDAD_OBJETO_DOMINIO)
                {
                    lvRestriccionDominioPropiedadObjeto.Items.Add(restriccion.ToString());
                }
                else if (restriccion.TipoPropiedadRelacionada == TipoPropiedadRelacionada.PROPIEDAD_OBJETO_RANGO)
                {
                    lvRestriccionRangoPropiedadObjeto.Items.Add(restriccion.ToString());
                }
            }

            // Restricciones de propiedad de dato
            foreach (RestriccionPropiedadObjeto restriccion in propiedad.RestriccionesPropiedadObjeto)
            {
                if (restriccion.TipoPropiedadRelacionada == TipoPropiedadRelacionada.PROPIEDAD_OBJETO_DOMINIO)
                {
                    lvRestriccionDominioPropiedadObjeto.Items.Add(restriccion.ToString());
                }
                else if (restriccion.TipoPropiedadRelacionada == TipoPropiedadRelacionada.PROPIEDAD_OBJETO_RANGO)
                {
                    lvRestriccionRangoPropiedadObjeto.Items.Add(restriccion.ToString());
                }
            }
        }

        /// <summary>
        /// Carga las restricciones aplicadas a los individuos
        /// </summary>
        /// <param name="individuo"></param>
        private void cargaListaRestriccionesIndividuo(Individuo individuo)
        {
            lvRestriccionesTiposIndividuo.Items.Clear();

            // Restricciones de propiedad de dato
            foreach (RestriccionPropiedadDato restriccion in individuo.RestriccionesPropiedadDato)
            {
                if (restriccion.TipoPropiedadRelacionada == TipoPropiedadRelacionada.INDIVIDUO_TIPO)
                {
                    lvRestriccionesTiposIndividuo.Items.Add(restriccion.ToString());
                }
            }

            // Restricciones de propiedad de dato
            foreach (RestriccionPropiedadObjeto restriccion in individuo.RestriccionesPropiedadObjeto)
            {
                if (restriccion.TipoPropiedadRelacionada == TipoPropiedadRelacionada.PROPIEDAD_DATO_DOMINIO)
                {
                    lvRestriccionesTiposIndividuo.Items.Add(restriccion.ToString());
                }
            }
        }

        /// <summary>
        /// Oculta las propiedades
        /// </summary>
        private void ocultarPropiedades()
        {
            gbEspacioNombres.Visible = false;
            gbClases.Visible = false;
            gbPropiedadesDato.Visible = false;
            gbPropiedadObjeto.Visible = false;
            gbIndividuos.Visible = false;
            gbOWL.Visible = false;
        }
    }
}
